/* Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * This file is a part of the CANN Open Software.
 * Licensed under CANN Open Software License Agreement Version 1.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 * ===================================================================================================================*/
#include <ascend_ir/expression.h>

#include <memory>
#include <limits>
#include <string>
#include <vector>
#include <map>
#include <array>
#include <symengine/rational.h>
#include <expression_impl.h>
#include "common/util/mem_utils.h"

namespace ge {
namespace expression {
ExpressionPtr Expression::CreateExpression(const ExpressionImplPtr &e) {
  // 确保传出去的Expression对象的impl非空
  IF_NULL_RETURN_NULL(e);
  return std::shared_ptr<Expression>(new (std::nothrow) Expression(e));
}

template <typename T>
ExpressionPtr Expression::CreateExpressionInner(T value, const std::string &name) {
  const auto impl = ExpressionImpl::CreateExpressionImpl<T>(value);
  auto expr = Expression::CreateExpression(impl);
  if (expr != nullptr) {
    expr->name_ = name;
  }
  return expr;
}

ExpressionPtr Expression::CreateExpression(const int32_t const_value, const std::string &name) {
  return Expression::CreateExpressionInner<const int32_t>(const_value, name);
}

ExpressionPtr Expression::CreateExpression(const int64_t const_value, const std::string &name) {
  return Expression::CreateExpressionInner<const int64_t>(const_value, name);
}

ExpressionPtr Expression::CreateExpression(const uint32_t const_value, const std::string &name) {
  return Expression::CreateExpressionInner<const uint32_t>(const_value, name);
}

ExpressionPtr Expression::CreateExpression(const uint64_t const_value, const std::string &name) {
  return Expression::CreateExpressionInner<const uint64_t>(const_value, name);
}

ExpressionPtr Expression::CreateExpression(const double const_value, const std::string &name) {
  return Expression::CreateExpressionInner<const double>(const_value, name);
}

ExpressionPtr Expression::CreateExpression(const std::string &name)  {
  return Expression::CreateExpressionInner<const std::string&>(name, name);
}

Expression::~Expression() {}

std::string Expression::Str(const StrType type) const {
  return impl_->Str(type);
}

ExprType Expression::GetExprType() const {
  return impl_->GetExprType();
}

std::string Expression::GetName() const {
  return name_;
}

ExpressionPtr Expression::Replace(const std::map<ExpressionPtr, ExpressionPtr> &replace_vars) const {
  std::map<ExpressionImplPtr, ExpressionImplPtr> impl_map;
  for (auto &item : replace_vars) {
    if ((item.first != nullptr) && (item.second != nullptr)) {
      impl_map.emplace(item.first->impl_, item.second->impl_);
    }
  }
  auto impl = impl_->Replace(impl_map);
  return Expression::CreateExpression(impl);
}

graphStatus Expression::GetResult(const std::map<ExpressionPtr, ExpressionPtr> &vars_value,
                                  double &result) const {
  ExpressionPtr replace_expr = Replace(vars_value);
  if (replace_expr == nullptr) {
    return GRAPH_FAILED;
  }
  if (replace_expr->impl_->GetResult(result)) {
    return GRAPH_SUCCESS;
  }
  return GRAPH_FAILED;
}


ExpressionPtr Expression::Simplify() const {
  auto impl = impl_->Simplify();
  return Expression::CreateExpression(impl);
}

bool Expression::ContainVar(const ExpressionPtr &e) const {
  if (e == nullptr) {
    return false;
  }
  return impl_->ContainVar(e->impl_);
}

bool Expression::operator==(const Expression &e) const {
  return (*impl_ == *e.impl_);
}

bool Expression::Eq(const ExpressionPtr &e) const {
  if (e == nullptr) {
    return false;
  }
  return (*this == *e);
}


std::vector<ExpressionPtr> Expression::GetPrimaryArgs() const {
  std::vector<ExpressionPtr> prim_args;
  for (auto &arg : impl_->GetPrimaryArgs()) {
    prim_args.emplace_back(Expression::CreateExpression(arg));
  }
  return prim_args;
}

Expression::Expression(const ExpressionImplPtr &e) : impl_(e) {}


ExpressionPtr operator+(const ExpressionPtr &e1, const ExpressionPtr &e2) {
  return Add(e1, e2);
}

ExpressionPtr operator-(const ExpressionPtr &e1, const ExpressionPtr &e2) {
  return Sub(e1, e2);
}

ExpressionPtr operator*(const ExpressionPtr &e1, const ExpressionPtr &e2) {
  return Mul(e1, e2);
}

ExpressionPtr operator/(const ExpressionPtr &e1, const ExpressionPtr &e2) {
  return Div(e1, e2);
}

ExpressionPtr Add(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Add(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Sub(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Sub(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Mul(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Mul(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Div(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Div(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Max(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Max(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Min(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Min(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Pow(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Pow(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Log(const ExpressionPtr &a) {
  IF_NULL_RETURN_NULL(a);
  auto impl = Log(a->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Log(const ExpressionPtr &a, const ExpressionPtr &b) {
  IF_NULL_RETURN_NULL(a);
  IF_NULL_RETURN_NULL(b);
  auto impl = Log(a->impl_, b->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Ceiling(const ExpressionPtr &a) {
  IF_NULL_RETURN_NULL(a);
  auto impl = Ceiling(a->impl_);
  return Expression::CreateExpression(impl);
}

ExpressionPtr Rational(const int32_t a, const int32_t b) {
  SymEngineExprPtr sym_expr = SymEngine::Rational::from_two_ints(a, b);
  auto impl = ExpressionImpl::CreateExpressionImpl<const SymEngineExprPtr&>(sym_expr);
  return Expression::CreateExpression(impl);
}

std::ostream &operator<<(std::ostream &os, const Expression &e) {
  os << *e.impl_;
  return os;
}
}  // namepsace expression
}  // namepsace ge
